    /*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package aeronef.appStates;

import com.jme3.app.Application;
import com.jme3.app.state.AppStateManager;
import com.jme3.collision.CollisionResult;
import com.jme3.collision.CollisionResults;
import com.jme3.font.BitmapFont;
import com.jme3.input.ChaseCamera;
import com.jme3.input.KeyInput;
import com.jme3.input.MouseInput;
import com.jme3.input.controls.ActionListener;
import com.jme3.input.controls.KeyTrigger;
import com.jme3.input.controls.MouseButtonTrigger;
import com.jme3.math.Ray;
import com.jme3.math.Vector2f;
import com.jme3.math.Vector3f;
import com.jme3.scene.Node;
import aeronef.AudioManager;
import aeronef.ScenarioManager;
import aeronef.IngameHud;
import aeronef.model.Battery;
import aeronef.model.Ship;
import aeronef.model.Turret;
import com.jme3.bullet.BulletAppState;
import com.jme3.input.controls.AnalogListener;
import java.util.ArrayList;
import java.util.List;

/**
 *
 * @author Hagan
 */
public class GameState extends BasicAppState {

    protected Boolean isRunning = true;
    
    protected int resWidth = 0;
    protected int resHeight = 0;
    
    protected ChaseCamera mainCamera;
    
    protected BulletAppState bulletAppState;

    protected Ship playerShip = new Ship(stateManager);
    protected List<Ship> ships = new ArrayList<Ship>();
    
    protected AudioManager audioManager;
    protected ScenarioManager scenarioManager;
    
    protected BitmapFont hudFont;
    protected IngameHud hud;
    
    @Override
    public void initialize(AppStateManager stateManager, Application app) {
            
        super.initialize(stateManager, app);
        
        initPhysics();
        
        initHud();
        initKeys();
        initAudio();
        initCamera();
        
        inputManager.setCursorVisible(true);
        
        scenarioManager = new ScenarioManager(this);
        scenarioManager.buildScenario("grimmnight");
    }
    
    private void initPhysics() {
        bulletAppState = new BulletAppState();
        stateManager.attach(bulletAppState);
    }
    
    private void initHud() {
        hud = new IngameHud(assetManager, guiNode, resWidth, resHeight);
        hud.init();
    }
    
    private void initKeys() {

        inputManager.addMapping("Select", new MouseButtonTrigger(MouseInput.BUTTON_LEFT));
        inputManager.addMapping("CameraMove", new MouseButtonTrigger(MouseInput.BUTTON_RIGHT));
        inputManager.addMapping("CameraTarget", new KeyTrigger(KeyInput.KEY_LMENU));
        inputManager.addMapping("Pause", new KeyTrigger(KeyInput.KEY_PAUSE));
        
        inputManager.addMapping("TurnLeft", new KeyTrigger(KeyInput.KEY_A));
        inputManager.addMapping("TurnRight", new KeyTrigger(KeyInput.KEY_D));
        inputManager.addMapping("RollLeft", new KeyTrigger(KeyInput.KEY_Q));
        inputManager.addMapping("RollRight", new KeyTrigger(KeyInput.KEY_E));
        inputManager.addMapping("SpeedUp", new KeyTrigger(KeyInput.KEY_R));
        inputManager.addMapping("SpeedDown", new KeyTrigger(KeyInput.KEY_F));
        inputManager.addMapping("Climb", new KeyTrigger(KeyInput.KEY_S));
        inputManager.addMapping("Dive", new KeyTrigger(KeyInput.KEY_W));
        inputManager.addMapping("RollLeft", new KeyTrigger(KeyInput.KEY_Q));
        inputManager.addMapping("RollRight", new KeyTrigger(KeyInput.KEY_E));
        
        inputManager.addMapping("TrainClockwise", new KeyTrigger(KeyInput.KEY_L));
        inputManager.addMapping("TrainAnticlockwise", new KeyTrigger(KeyInput.KEY_J));
        inputManager.addMapping("Elevate", new KeyTrigger(KeyInput.KEY_I));
        inputManager.addMapping("Depress", new KeyTrigger(KeyInput.KEY_K));
        inputManager.addMapping("Shoot", new KeyTrigger(KeyInput.KEY_SPACE));
        
        inputManager.addListener(actionListener, "Select");
        inputManager.addListener(actionListener, new String[]{"CameraMove", "CameraTarget"});
        inputManager.addListener(actionListener, new String[]{"Pause"});
        
        inputManager.addListener(actionListener, new String[]{"TurnLeft", "TurnRight"});
        inputManager.addListener(actionListener, new String[]{"SpeedUp", "SpeedDown"});
        inputManager.addListener(actionListener, new String[]{"Climb", "Dive"});
        inputManager.addListener(actionListener, new String[]{"RollLeft", "RollRight"});
        inputManager.addListener(actionListener, new String[]{"Shoot"});
        
        inputManager.addListener(analogListener, new String[]{"TrainLeft", "TrainRight"});
        inputManager.addListener(analogListener, new String[]{"TrainClockwise", "TrainAnticlockwise"});
        inputManager.addListener(analogListener, new String[]{"Elevate", "Depress"});
        
    }    
    
    private void initAudio() {
        
        audioManager = new AudioManager(assetManager);
        //audioManager.playAmbient();
    }
    
    private void initCamera() {

        mainCamera = new ChaseCamera(cam, rootNode, inputManager);
        
        mainCamera.setSmoothMotion(true);
        mainCamera.setTrailingEnabled(false);
        mainCamera.setToggleRotationTrigger(new MouseButtonTrigger(MouseInput.BUTTON_RIGHT));
        
        mainCamera.setInvertVerticalAxis(true);
        
        mainCamera.setRotationSensitivity(500);
        mainCamera.setMaxVerticalRotation(45);
        mainCamera.setMinVerticalRotation(-45);
        mainCamera.setZoomSensitivity(500);
        
        mainCamera.setDefaultDistance(50);
        mainCamera.setMaxDistance(400);
        mainCamera.setMinDistance(1);
        
    }

    @Override
    public void update(float tpf) {
        if (isRunning) {
            
            for (Ship ship : ships) {
                ship.act();
            }
            hud.updateShipDetails(playerShip);
        }
    }
    
    private ActionListener actionListener = new ActionListener() {

        public void onAction(String name, boolean keyPressed, float tpf) {

            if (name.equals("Select") && (!keyPressed)) {

                // 1. Reset results list.
                CollisionResults results = new CollisionResults();
                // 2 Aim ray from camera to click.
                Vector2f click2d = inputManager.getCursorPosition();
                Vector3f click3d = cam.getWorldCoordinates(new Vector2f(click2d.x, click2d.y), 0f).clone();
                Vector3f dir = cam.getWorldCoordinates(new Vector2f(click2d.x, click2d.y), 1f).subtractLocal(click3d).normalizeLocal();
                Ray ray = new Ray(click3d, dir);
                // 3. Collect intersections between Ray and Shootables in results list.
                rootNode.collideWith(ray, results);
                // 4. Print results.
                System.out.println("----- Collisions? " + results.size() + "-----");
                if (results.size() > 0) {
                    CollisionResult result = results.getCollision(0);
                    Node clickNode = result.getGeometry().getParent();
                    if (clickNode instanceof Ship) {
                        playerShip = (Ship) clickNode;
                        mainCamera.setSpatial(clickNode);
                    }
                }
            }

            if (name.equals("TurnLeft") && !keyPressed) { playerShip.turn(new Float(1)); }
            if (name.equals("TurnRight") && !keyPressed) { playerShip.turn(new Float(-1)); }
            if (name.equals("RollLeft") && !keyPressed) { playerShip.roll(new Float(1)); }
            if (name.equals("RollRight") && !keyPressed) { playerShip.roll(new Float(-1)); }
            if (name.equals("SpeedUp") && !keyPressed) { playerShip.speed(new Float(1)); }
            if (name.equals("SpeedDown") && !keyPressed) { playerShip.speed(new Float(-1)); }
            if (name.equals("Climb") && !keyPressed) { playerShip.climb(new Float(1)); }
            if (name.equals("Dive") && !keyPressed) { playerShip.climb(new Float(-1)); }
            
            if (name.equals("Shoot") && !keyPressed) {
                for (Battery battery : playerShip.getBatteries()) {
                    for (Turret turret : battery.getTurrets()) {
                        turret.shoot();
                    }
                }
            }
            
            if (name.equals("Pause") && !keyPressed) {
                togglePause();
            }
            
        }
    };
    
    private AnalogListener analogListener = new AnalogListener() {
        public void onAnalog(String name, float value, float tpf) {
            if (name.equals("TrainClockwise")) { playerShip.trainClockwise(tpf); }
            if (name.equals("TrainAnticlockwise")) { playerShip.trainAnticlockwise(tpf); }
            if (name.equals("Elevate")) { playerShip.elevate(); }
            if (name.equals("Depress")) { playerShip.depress(); }
            
        }
    };
    
    private void togglePause() {
        if (isRunning) {
            isRunning = false;
            getBulletAppState().setEnabled(false);
            hud.showMessage("Paused");
        } else {
            isRunning = true;
            getBulletAppState().setEnabled(true);
            hud.clearGui();
        }
    }

    public int getResWidth() { return resWidth; }
    public int getResHeight() { return resHeight; }
    public BulletAppState getBulletAppState() { return bulletAppState; }
    public List<Ship> getNefs() { return ships; }
    public Node getPlayerNef() { return playerShip; }
    
    public void setResWidth(int width) { this.resWidth = width; }
    public void setResHeight(int height) { this.resHeight = height; }
    public void setBulletAppState(BulletAppState bulletAppState) { this.bulletAppState = bulletAppState; }
    public void setPlayerNef(Ship playerNef) { this.playerShip = playerNef; }


    
}

